package cn.xuguowen.aspect;

import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;

/**
 * ClassName: LogAspect
 * Package: cn.xuguowen.aspect
 * Description:
 * 日志切面
 *  1.可以将日志打印到控制台和日志文件中，后期借助elk等工具分析日志文件，采集日志文件数据存储到数据库中
 *  2.直接在这里将日志文件保存到数据库中
 * @Author 徐国文
 * @Create 2023/4/1 14:15
 * @Version 1.0
 */
@Aspect
@Slf4j
@Component
// SqlBeautyInterceptor拦截器也用到了自动装配
@ConditionalOnProperty(value = "log.aspect.enable",havingValue = "true",matchIfMissing = false)
public class LogAspect {

    @Pointcut("execution(* cn.xuguowen..*.*Controller.*(..)) || execution(* cn.xuguowen..*.*Service.*(..))")
    public void pointCut() {}

    @Around("pointCut()")
    public void around(ProceedingJoinPoint pjp) throws Throwable {
        // 1.拿到方法的入参
        Object[] args = pjp.getArgs();
        String reqArgs = new Gson().toJson(args);

        // 2.拿到方法名称和类名称
        Signature signature = pjp.getSignature();
        String methodName = signature.getDeclaringTypeName() + "." + signature.getName();

        // 3.记录入参日志
        log.info("{},reqArgs:{}",methodName,reqArgs);

        // 4.记录方法执行时间
        long startTime = System.currentTimeMillis();
        // TODO 执行方法！此处的异常要抛出去，如果catch的话就将也业务方的异常捕获了，导致MVC的全局异常处理器无法拦截异常给出提示信息
        Object response = pjp.proceed();
        long endTime = System.currentTimeMillis();

        // 5.记录出参日志
        String respStr = new Gson().toJson(response);
        log.info("{},response:{},costTime:{}",methodName,respStr,(endTime - startTime));
    }

}
